package com.basker.pisces.core.meta;

import java.util.Map;

import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import com.basker.pisces.core.IDataContract;

public abstract class AbstractField implements IField {

    protected String name;
    protected String displayName;
    private int order = -1;

    protected AbstractField(String name, String displayName) {
        this.name = name;
        this.displayName = displayName;
    }

    @Override
    public String getDisplayName() {
        return !StringUtils.isEmpty(displayName) ? displayName : name;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public int getOrder() {
        return order;
    }

    @SuppressWarnings("unchecked")
    @Override
    public Object getValue(Object dataObject) {
        Assert.notNull(dataObject, "parameter 'dataObject' is required");

        if (dataObject instanceof IDataContract) {
            return getValueFromDataContract((IDataContract) dataObject);
        }

        if (dataObject instanceof Map<?, ?>) {
            return getValueFromMap((Map<String, Object>) dataObject);
        }

        throw throwObjectClassNotImplException(dataObject);
    }

    public void setDisplayName(String displayName) {
        this.displayName = displayName;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void setOrder(int order) {
        this.order = order;
    }

    @SuppressWarnings("unchecked")
    @Override
    public void setValue(Object dataObject, Object value) {
        Assert.notNull(dataObject, "parameter 'dataObject' is required");

        if (dataObject instanceof IDataContract) {
            setValueForDataContract((IDataContract) dataObject, value);
            return;
        }

        if (dataObject instanceof Map<?, ?>) {
            setValueForMap((Map<String, Object>) dataObject, value);
            return;
        }

        throw throwObjectClassNotImplException(dataObject);
    }

    @Override
    public String toString() {
        return this.getClass().getSimpleName() + ":" + this.name;
    }

    protected Object getValueFromDataContract(IDataContract dataContract) {
        return dataContract.getFieldValue(this);
    }

    protected Object getValueFromMap(Map<String, Object> map) {
        return map.get(this.name);
    }

    private void setValueForDataContract(IDataContract dataContract, Object value) {
        dataContract.setFieldValue(this, value);
    }

    private void setValueForMap(Map<String, Object> map, Object value) {
        map.put(this.name, value);
    }

    private RuntimeException throwObjectClassNotImplException(Object dataObject) {
        return new RuntimeException("dataObject:" + dataObject.getClass().getName() + ",is not impled");
    }

}
